﻿using SvgViewer.Entities;
using SvgViewer.ViewModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using SvgViewer.Core;

namespace SvgViewer.Views;

/// <summary>
/// 主视图
/// </summary>
public partial class MainView : IViewService
{
    /// <summary>
    /// 构造
    /// </summary>
    public MainView()
    {
        InitializeComponent();
        InitEvents();
    }

#region IViewService

    void IViewService.Show(string token, params object[] args)
    {
        token = token.ToLowerInvariant();
        switch (token)
        {
            case "detail":
                ShowDetail(args[0] as SvgInfo);
                break;
            case "export":
                ShowExport(args[0] as SvgInfo);
                break;
            case "about":
                ShowAbout();
                break;
        }
    }

    void IViewService.ShowTip(string message)
    {
        Snackbar.MessageQueue?.Enqueue(message, null, null, null, false, true, TimeSpan.FromSeconds(3));
    }

#endregion

    private void ShowDetail(SvgInfo info)
    {
        if (info == null)
        {
            return;
        }

        var view = new DetailView {
            DataContext = new DetailViewModel(info), Owner = this
        };
        view.ShowDialog();
    }

    private void ShowAbout()
    {
        var view = new AboutView {
            Owner = this
        };
        view.ShowDialog();
    }

    private void ShowExport(SvgInfo info)
    {
        if (info == null)
        {
            return;
        }

        var view = new ExportView {
            DataContext = new ExportViewModel(info), Owner = this
        };
        view.ShowDialog();
    }

    private void InitEvents()
    {
        txtSearch.PreviewMouseDoubleClick += SearchPreviewMouseDoubleClick;
        this.ContentRendered              += MainViewContentRendered;
    }

    private void SearchPreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Released)
        {
            txtSearch.Focus();
            txtSearch.SelectAll();
        }
    }

    private void SetCurrentDirectory(string dirPath)
    {
        if (string.IsNullOrEmpty(dirPath))
        {
            return;
        }

        var dir = new DirectoryInfo(dirPath);
        if (dir.Exists == false)
        {
            return;
        }

        var parent = dir.Parent;
        var paths   = new List<string>();
        do
        {
            if (parent != null)
            {
                paths.Insert(0, parent.FullName);

                parent = parent.Parent;
            }
        } while (parent != null);

        ItemsControl itemsControl = TreeView;
        foreach (var path in paths)
        {
            if (itemsControl != null)
            {
                itemsControl = FindTreeViewItem(path, itemsControl, false);
            }
        }

        if (itemsControl != null)
        {
            FindTreeViewItem(dirPath, itemsControl, true);
        }
    }

    private ItemsControl FindTreeViewItem(string path, ItemsControl parent, bool select)
    {
        for (var i = 0; i < parent.Items.Count; i++)
        {
            var info = (FolderInfo)parent.Items[i];
            if (string.Compare(info.Path, path, StringComparison.OrdinalIgnoreCase) == 0)
            {
                if (parent.ItemContainerGenerator.ContainerFromItem(info) is TreeViewItem item)
                {
                    return SelectOrExpandTreeViewItem(item, select);
                }

                parent.ApplyTemplate();
                var itemsPresenter = (ItemsPresenter)parent.Template.FindName("ItemsHost", parent);
                if (itemsPresenter != null)
                {
                    itemsPresenter.ApplyTemplate();
                }
                else
                {
                    parent.UpdateLayout();
                    itemsPresenter = FindVisualChild<ItemsPresenter>(parent);
                }

                var itemsHostPanel = (Panel)VisualTreeHelper.GetChild(itemsPresenter, 0);

                if (itemsHostPanel is VirtualizingStackPanelEx virtualPanel)
                {
                    virtualPanel.BringIntoView(i);
                    item = parent.ItemContainerGenerator.ContainerFromIndex(i) as TreeViewItem;
                    return SelectOrExpandTreeViewItem(item, select);
                }
            }
        }

        return null;
    }

    private TreeViewItem SelectOrExpandTreeViewItem(TreeViewItem item, bool select)
    {
        if (item != null)
        {
            if (select)
            {
                item.IsSelected = true;
            }
            else
            {
                item.SetValue(TreeViewItem.IsExpandedProperty, true);
                item.IsExpanded = true;
                item.UpdateLayout();
            }

            item.BringIntoView();
        }

        return item;
    }

    private T FindVisualChild<T>(Visual visual) where T : Visual
    {
        for (var i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
        {
            var child = (Visual)VisualTreeHelper.GetChild(visual, i);

            if (child is T correctlyTyped)
            {
                return correctlyTyped;
            }

            var descendent = FindVisualChild<T>(child);
            if (descendent != null)
            {
                return descendent;
            }
        }

        return null;
    }

    private void MainViewContentRendered(object sender, EventArgs e)
    {
        this.WindowState = WindowState.Maximized;
        if (this.DataContext is MainViewModel viewModel)
        {
            viewModel.ViewService = this;
            SetCurrentDirectory(Properties.Settings.Default.SelectedPath);
        }
    }

    private void ThumbOnDragCompleted(object sender, DragCompletedEventArgs e)
    {
        ((MainViewModel)this.DataContext).ImageSize = ((Slider)sender).Value;
    }
}